﻿#region Using

using System.Collections.Generic;

using GameCommon.Base;
using GameCommon.Components;
using GameCommon.Effects;
using GameCommon.ManagerInterfaces;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

#endregion

namespace GameCommon.Manager
{
    internal class DrawingManager : IDrawingManager
    {
        private readonly SpriteBatch spriteBatch;

        private readonly SpriteCollection sprites;

        private Camera camera;

        public DrawingManager(SpriteBatch spriteBatch)
        {
            this.spriteBatch = spriteBatch;
            this.sprites = new SpriteCollection();
        }

        public void Add(Texture2D texture2D, Rectangle destinationRectangle, Color color)
        {
            this.Add(texture2D, destinationRectangle, null, color, 1);
        }

        public void Add(Texture2D texture2D, Rectangle destinationRectangle, Color color, int layer)
        {
            this.Add(texture2D, destinationRectangle, null, color, layer);
        }

        public void Add(Texture2D texture2D, Rectangle destinationRectangle, Rectangle? sourceRectangle, Color color)
        {
            this.Add(texture2D, destinationRectangle, sourceRectangle, color, 1);
        }

        public void Add(Texture2D texture2D, Rectangle destinationRectangle, Rectangle? sourceRectangle, Color color, int layer)
        {
            if (texture2D != null)
            {
                this.sprites.Add(new Sprite(texture2D, destinationRectangle, sourceRectangle, color, layer));
            }
        }

        public void DrawCurrentScreenToTexture(RenderTarget2D target)
        {
            this.sprites.Order();

            Managers.ContentManager.SetRenderTarget2D(target);
            Managers.ContentManager.ClearGraphics();

            this.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.LinearWrap, null, null, null, this.camera.Matrix);
            foreach (Sprite sprite in this.sprites)
            {
                this.spriteBatch.Draw(sprite.Texture2D, sprite.DestinationRectangle, sprite.SourceRectangle, sprite.Color, sprite.Rotation, sprite.Origin, sprite.SpriteEffects, sprite.Layer);
            }

            this.spriteBatch.End();
        }

        public IDrawingManager Initialize(Camera cam)
        {
            this.camera = cam;
            this.sprites.Clear();
            return this;
        }

        public void DrawAllScreens(IEnumerable<RenderTarget2D> screensAsTexture)
        {
            Managers.ContentManager.SetRenderTarget2D(null);

            this.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);

            foreach (var renderTarget2D in screensAsTexture)
            {
                this.spriteBatch.Draw(renderTarget2D, Vector2.Zero, Color.White);
            }

            this.spriteBatch.End();
        }

        public void ApplyEffects(IEnumerable<IEffect> list, RenderTarget2D screenAsTexture)
        {
            foreach (var effect in list)
            {
                this.ApplyEffect(effect.Effect, screenAsTexture);
            }
        }

        private void ApplyEffect(Effect effect, RenderTarget2D screenAsTexture)
        {
            if (effect == null)
            {
                return;
            }

            Managers.ContentManager.SetRenderTarget2D(screenAsTexture);
            this.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);

            foreach (var pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                this.spriteBatch.Draw(screenAsTexture, Vector2.Zero, Color.White);
            }

            this.spriteBatch.End();
        }
    }
}